AWS Lambda Layersを他アカウントと共有する #reinvent
はじめに
re:Invent 2018で発表されたAWS Lambda Layersを利用すると、複数のLambda関数が利用するような共通ライブラリを外出しして管理出来ます。
さらに、外出したレイヤーは、他のAWSアカウントからも利用出来ます。
今回は、作成したLambda Layerを他のAWSアカウントと共有する方法を紹介します。
ポイント
- Layerのバージョンごとに共有設定が必要
- 共有アカウントの粒度は個別・組織・全アカウントなど柔軟
- リージョンをまたいだ共有はできない
作業の流れ
以下のステップでLambda Layerを他アカウントと共有します
- Lambda Layerの登録
- 同じアカウントのLambda関数からLayerを利用
- Layerを他アカウントと共有
- 他アカウントのLambda関数からLayerを利用
- 共有設定を除外した場合の動作
Lambda のランタイムには Python 3.7 を利用し、Lambda Layer には requests ライブラリを利用します。
1. Lambda Layerの登録
まずはrequestsをLambda Layer向けにパッケージングします。
ライブラリのバージョン情報をlayerのdescriptionに付与します。
$ pip install -t python requests==2.21.0 $ zip -r python.zip python $ aws lambda publish-layer-version \ --layer-name requests \ --description "requests 2.21.0" --zip-file fileb://python.zip \ --compatible-runtimes python3.7 { "Content": { "Location": "https://awslambda-eu-cent-1-layers.s3.eu-central-1.amazonaws.com/snapshots/...", "CodeSha256": "e72w5zIow1ua4WJ+jYDSJEgQZjVUudlBkCV8s7lIQIk=", "CodeSize": 903621 }, "LayerArn": "arn:aws:lambda:eu-central-1:123456789012:layer:requests", "LayerVersionArn": "arn:aws:lambda:eu-central-1:123456789012:layer:requests:1", "Description": "requests 2.20.0", "CreatedDate": "2018-12-12T15:37:49.027+0000", "Version": 1, "CompatibleRuntimes": [ "python3.7" ] }
Lambda関数からLambda Layerを利用する際には、LayerVersionArn
を利用します。
このARNを控えておいてください。
2. 同じアカウントのLambda関数からLayerを利用
Layerを利用することで requests ライブラリが利用できるようになることを確認します。
requestsライブラリを利用する関数を用意します。
import requests def lambda_handler(event, context): return 'ok'
Layer呼び出しに成功すると、インポート文も成功するため、Lambdaの実行が成功します。
レイヤー利用前
Layer を利用せずにLambda関数を登録します。
$ zip test.zip test.py $ aws lambda create-function \ --function-name test \ --runtime python3.7 \ --role arn:aws:iam::123456789012:role/lambda_basic_execution \ --handler test.lambda_handler \ --zip-file fileb://test.zip { "FunctionName": "test", "FunctionArn": "arn:aws:lambda:eu-central-1:123456789012:function:test", "Runtime": "python3.7", "Role": "arn:aws:iam::123456789012:role/lambda_basic_execution", "Handler": "test.lambda_handler", "CodeSize": 271, "Description": "", "Timeout": 3, "MemorySize": 128, "LastModified": "2018-12-12T15:24:39.238+0000", "CodeSha256": "AdDE1ghNn14icmCWkTemCVVVpRd1ZU1NXFbKnMuzVEA=", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "8532d2d6-d607-4a15-a7d3-cd6d1d4f0297" }
Lambda関数を実行すると、requestsライブラリをインポート出来ないため、エラーになります。
$ aws lambda invoke --function-name test output.txt { "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" } $ cat output.txt {"errorMessage": "Unable to import module 'test'"}
レイヤー利用後
次にrequestsライブラリのLayerを利用するようにLambda関数を更新します。
--layers
引数でLayerを指定します。
$ aws lambda update-function-configuration \ --function-name test \ --layers arn:aws:lambda:eu-central-1:123456789012:layer:requests:1 { ... "Layers": [ { "Arn": "arn:aws:lambda:eu-central-1:123456789012:layer:requests:1", "CodeSize": 903621 } ] }
Lambda 関数を再実行します。
$ aws lambda invoke --function-name test output.txt { "StatusCode": 200, "ExecutedVersion": "$LATEST" } $ cat output.txt "ok"
Layer経由でrequestsライブラリを読み込めたため、Lambdaの実行が成功しました。
3. Layerを他アカウントと共有
本題です。
Lambda Layerを他アカウントと共有します。
共有設定は (レイヤー, バージョン) の組み合わせごとに指定が必要です。 つまり、レイヤーを更新するたびに、共有設定も再設定が必要です。
また、この組み合わせに対して、複数の共有設定を指定出来ます。
例えば、
- Layer名 : requests
- Layerバージョン : 1
を
- AWSアカウント : 111111111111
から利用できるようにする場合、以下の様に指定します。
$ aws lambda add-layer-version-permission \ --layer-name requests \ --statement-id share-with-dev \ --version-number 1 \ --principal 111111111111 \ --action lambda:GetLayerVersion { "Statement": "{\"Sid\":\"share-with-dev\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::111111111111:root\"},\"Action\":\"lambda:GetLayerVersion\",\"Resource\":\"arn:aws:lambda:eu-central-1:123456789012:layer:requests:1\"}", "RevisionId": "01285c2c-3be3-4279-9d5b-8ea45654431a" }
ポリシー部分を見やすいように整形します。
{ "Sid": "share-with-dev", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:root" }, "Action": "lambda:GetLayerVersion", "Resource": "arn:aws:lambda:eu-central-1:123456789012:layer:requests:1" }
共有先AWSアカウント(Principal
)が、Lambda Layer(Resource
) を lambda:GetLayerVersion
を実行できるように許可しています。
共有先アカウントの指定例
lambda:AddLayerVersionPermission
実行時の共有先アカウントの指定例をいくつか紹介します。
共有先アカウントが一つの場合
--principal 111111111111
ある組織配下の全アカウント
--organization-id o-1234567890 \ --principal '*'
任意のアカウント
--principal '*'
4. 他アカウントのLambda関数からLayerを利用
Layerの共有先アカウントから Layer を呼び出してみます。
ステップ2と同じように Lambda 関数を登録します。
--layers
引数には、共有しているLayerのARNを指定します。
$ aws lambda create-function \ --function-name test \ --runtime python3.7 \ --role arn:aws:iam::111111111111:role/ROLE \ --handler test.lambda_handler \ --zip-file fileb://test.zip \ --layers arn:aws:lambda:eu-central-1:123456789012:layer:requests:1 { "FunctionName": "test", ... "Layers": [ { "Arn": "arn:aws:lambda:eu-central-1:123456789012:layer:requests:1", "CodeSize": 903621 } ] }
Layer を呼び出せることを確認します。
$ aws lambda invoke --function-name test output.txt { "StatusCode": 200, "ExecutedVersion": "$LATEST" } $ cat output.txt "ok"
無事成功しています。
Lambda関数登録時、 - Layerが共有されていない - LayerとLambda関数のリージョンが違う 場合、以下の様なエラーが発生します。
$ aws lambda create-function \ ... An error occurred (AccessDeniedException) when calling the CreateFunction operation: User: arn:aws:sts::XXX is not authorized to perform: lambda:GetLayerVersion on resource: arn:aws:lambda:eu-central-1:共有元AWS-ACCOUNT-ID:layer:requests:1
5. 共有設定を除外した場合の動作
Lambda Layer の共有を解除すると、共有Layerを利用しているLambda関数への影響はどうなるでしょうか?
動作確認する限りでは、Lambda はLayerを利用可能でした。
共有設定を解除
共有設定を解除するには remove-layer-version-permission
API を呼び出します。
$ aws lambda remove-layer-version-permission \ --layer-name requests \ --version-number 1 \ --statement-id share-with-dev $
共有解除後に Lambda 関数を実行すると、正常実行されました。
Layer 共有時にアクション lambda:GetLayerVersion
を許可することから、Layer を利用する Lambda 関数を登録するタイミングで Layer も一緒にコピーされ、コピー後のLayerの共有設定の変更はLambdaの実行には影響がないものと思われます。
最後に
Lambda Layerを他のAWSアカウントと共有する方法を紹介しました。
他アカウントとレイヤーを共有することで
- 本番・開発でAWSアカウントを分割。開発環境でレイヤーのバージョンアップを試験。動作確認の取れた新バージョンを本番アカウントでも利用
- Lambda 関数の付随サービスを提供。レイヤーをインポートすれば利用できるように全アカウント向けに公開
といったことが可能になります。
- 複数アカウントでサービス開発しているユーザー
- 複数アカウントにサービス提供したいユーザー
どちらにとっても便利な機能ではないでしょうか。
それでは。